#pragma once 
#include "Log.hpp"
#include <mutex>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>


class TcpServer 
{
  private:
  TcpServer(int port)
    :_port(port)
    ,_listen_sock(-1)
  {}
  TcpServer(const TcpServer& ts) = delete;
  TcpServer& operator=(const TcpServer& ts) = delete;
  public:
  ~TcpServer(){if (_listen_sock > 0) close(_listen_sock);};

  static TcpServer* GetInstance(int port);
  void InitServer();
  void Socket();
  void Bind();
  void Listen();
  int  GetSock() {return _listen_sock;}
  private:
    int _port;
    int _listen_sock;
    static TcpServer* _svr;
};
TcpServer* TcpServer::_svr = nullptr;

TcpServer* TcpServer::GetInstance(int port){
  static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
  pthread_mutex_lock(&lock);
  if (_svr == nullptr){
    _svr = new TcpServer(port);
    _svr->InitServer();
  }
  LOG(INFO, "get tcp server instance success");
  pthread_mutex_unlock(&lock);
  return _svr;
}

void TcpServer::InitServer(){
  Socket();
  Bind();
  Listen();
  LOG(INFO, "TcpServer init success");
}

void TcpServer::Socket(){
  _listen_sock = socket(AF_INET, SOCK_STREAM, 0);
  if (_listen_sock < 0){
    //std::cerr << "socket errno" << errno << std::cout;
    LOG(FATAL, "socket errno");
    exit(1);
  }
  LOG(INFO, "socket success");
  //std::cout << "socket success" << std::endl;
  //socket地址复用 
  //若服务器崩了很容易出现端口(port)被占用的情况，导致
  //服务器无法立即重启, 使用此方法可以让服务器立即重启
  
  int opt = 1;
  setsockopt(_listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
}

void TcpServer::Bind(){
  struct sockaddr_in local;
  memset(&local, 0, sizeof(local));
  local.sin_family = AF_INET;
  local.sin_port = htons(_port);
  //云服务器的公网IP是虚拟出来的，不可直接绑定
  local.sin_addr.s_addr = INADDR_ANY;
  if (bind(_listen_sock, (struct sockaddr*)&local, sizeof(local)) < 0){
    //std::cerr << "bind errno" << errno << std::endl;
    LOG(FATAL, "bind errno");
    exit(2);
  }
  //std::cout << "bind success" << std::endl;
  LOG(INFO, "bind success");

}


void TcpServer::Listen(){
  if (listen(_listen_sock, 5) < 0){
    //std::cerr << "listen errno" << errno << std::endl;
    LOG(FATAL, "listen errno");
    exit(3);
  }
  //std::cout << "listen success" << std::endl;
  LOG(INFO, "listen success");
}
















